﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;


namespace MaiYao
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        // Windows API 导入
        [DllImport("user32.dll")]
        private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);

        [DllImport("user32.dll")]
        private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
        // 热键ID定义
        private const int _开始_ = 9001;
        private const int _暂停_ = 9002;
        private const int _结束_ = 9003;

        private const uint MOD_CONTROL = 0x0002;
        private const uint VK_左 = 0x25;
        private const uint VK_下 = 0x28;
        private const uint VK_右 = 0x27;

        public IntPtr 挂机程序句柄 = IntPtr.Zero;
        private Point _startPoint;
        private bool _isDragging = false;

        public IntPtr 买药窗口句柄 = IntPtr.Zero;
        public IntPtr 扔药窗口句柄 = IntPtr.Zero;
        public IntPtr 捡药窗口句柄 = IntPtr.Zero;

        public IntPtr 识别程序句柄 = IntPtr.Zero;

        public string UmiOcr窗口类名 = "Qt5152QWindowOwnDCIcon";
        public string UmiOcr窗口标题 = "Umi-OCR v2.1.5";
        public string UmiOcr进程名 = "Umi-OCR";
        public static string 游戏窗口类名 = "996CLIENT";

        public double 左边 = 0;
        public double 上边 = 0;
        public double 高度 = 0;
        public double 宽度 = 0;

        public 挂机项目_ 挂机项目 = 挂机项目_.无;

        public List<挂机人物> 挂机人物列表 = new List<挂机人物>();

        public static MainWindow _this;

        public static int 当前挂机人物索引 = 0;
        public static 线程_ 执行线程;
        public static SolidColorBrush 蓝色笔刷 = new SolidColorBrush(Color.FromRgb(0, 122, 204));
        public static Brush 默认笔刷;

        public static CancellationTokenSource cts = new CancellationTokenSource();

        public MainWindow()
        {
            InitializeComponent();
            _this = this;
            挂机程序句柄 = new WindowInteropHelper(this).Handle;
            LoadSettings();
        }

        private void LoadSettings()
        {
            // 读取窗口位置
            this.Left = Properties.Settings.Default.左边;

            this.Top = Properties.Settings.Default.上边;
            this.Height = Properties.Settings.Default.高度;
            this.Width = Properties.Settings.Default.宽度;

            买药.IsChecked = Properties.Settings.Default.买药;
            捡药.IsChecked = Properties.Settings.Default.捡药;
            扔药.IsChecked = Properties.Settings.Default.扔药;

            运行速率.Text = Properties.Settings.Default.运行速率;
            买药包裹空格数量.Text = Properties.Settings.Default.买药包裹空格数量;

            买药金币总量.Text = Properties.Settings.Default.买药金币总量;

            扔药包裹空格数.Text = Properties.Settings.Default.扔药包裹空格数;

            扔药剩余数量.Text = Properties.Settings.Default.扔药剩余数量;

            扔药坐标.Text = Properties.Settings.Default.扔药坐标;

            捡药包裹空格数.Text = Properties.Settings.Default.捡药包裹空格数;
            捡药坐标.Text = Properties.Settings.Default.捡药坐标;

        }

        private void MainWindow_SourceInitialized(object sender, EventArgs e)
        {
            // 获取窗口句柄
            IntPtr hwnd = new WindowInteropHelper(this).Handle;
            var source = HwndSource.FromHwnd(hwnd);
            source.AddHook(WndProc);
            // 注册全局热键
            RegisterHotKey(hwnd, _开始_, MOD_CONTROL, VK_左);
            RegisterHotKey(hwnd, _暂停_, MOD_CONTROL, VK_下);
            RegisterHotKey(hwnd, _结束_, MOD_CONTROL, VK_右);
        }

        private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            const int WM_HOTKEY = 0x0312;
            switch (msg)
            {
                case WM_HOTKEY:
                    switch (wParam.ToInt32())
                    {
                        case _开始_:
                            开始命令执行();
                            handled = true;
                            break;
                        case _暂停_:
                            暂停命令执行();
                            handled = true;
                            break;
                        case _结束_:
                            结束命令执行();
                            handled = true;
                            break;
                    }
                    break;
            }
            return IntPtr.Zero;
        }

        private void 开始命令执行()
        {
            其他_.打印("点击了开始执行命令");
            if (!开始或暂停.IsEnabled) return;

            if (开始或暂停.Content.ToString() != "开始(Ctrl + ←)") return;

            开始或暂停.Content = "暂停(Ctrl + ↓)";
            结束.IsEnabled = true;
            功能总面板.IsEnabled = false;
            cts = new CancellationTokenSource();
            this.挂机人物列表.Clear();
            var 是买药 = 买药.IsChecked == true;
            var 是扔药 = 扔药.IsChecked == true;
            var 是捡药 = 捡药.IsChecked == true;
            if (是买药)
            {
                调整窗口(买药窗口句柄);
                // 窗口_.置顶窗口(挂机程序句柄);
                try
                {
                    var 空格数量 = int.Parse(this.买药包裹空格数量.Text);
                    var 金币数量 = ulong.Parse(this.买药金币总量.Text);
                    var 买药人物 = new 挂机人物(买药窗口句柄, cts, 挂机项目_.买药, 空格数量, 金币数量, new 坐标_(111, 88));
                    this.挂机人物列表.Add(买药人物);
                }
                catch
                {
                    其他_.打印("买药设置发生错误");
                    return;
                }
            }
            else if (是扔药 && 是捡药)
            {
                调整窗口(捡药窗口句柄);
                其他_.延迟(500);
                调整窗口(扔药窗口句柄);
                其他_.延迟(500);
                try
                {
                    var 扔药空格数量 = int.Parse(this.扔药包裹空格数.Text);
                    var 扔药坐标文本 = this.扔药坐标.Text.Trim();
                    var xy = 扔药坐标文本.Split(new char[] { ':' });
                    if (xy.Length != 2)
                    {
                        其他_.打印("扔药仓库管理员坐标设置错误");
                        return;
                    }
                    var x = int.Parse(xy[0].Trim());
                    var y = int.Parse(xy[1].Trim());
                    var 扔药人物 = new 挂机人物(扔药窗口句柄, cts, 挂机项目_.扔药, 扔药空格数量, 0, new 坐标_(x, y));
                    this.挂机人物列表.Add(扔药人物);
                }
                catch
                {
                    其他_.打印("扔药设置发生错误");
                    return;
                }

                try
                {
                    var 捡药空格数量 = int.Parse(this.捡药包裹空格数.Text);
                    var 捡药坐标文本 = this.捡药坐标.Text.Trim();
                    var xy = 捡药坐标文本.Split(new char[] { ':' });

                    if (xy.Length != 2)
                    {
                        其他_.打印("捡药仓库管理员坐标设置错误");
                        return;
                    }
                    var x = int.Parse(xy[0].Trim());
                    var y = int.Parse(xy[1].Trim());
                    var 捡药人物 = new 挂机人物(捡药窗口句柄, cts, 挂机项目_.捡药, 捡药空格数量, 0, new 坐标_(x, y));
                    this.挂机人物列表.Add(捡药人物);
                }
                catch
                {
                    其他_.打印("捡药设置发生错误");
                    return;
                }

            }
            else if (是扔药)
            {
                调整窗口(扔药窗口句柄);
                其他_.延迟(500);
                //窗口_.置顶窗口(挂机程序句柄);
                try
                {
                    var 扔药空格数量 = int.Parse(this.扔药包裹空格数.Text);
                    var 扔药剩余数量 = int.Parse(this.扔药剩余数量.Text);
                    var 扔药坐标文本 = this.扔药坐标.Text.Trim();
                    var xy = 扔药坐标文本.Split(new char[] { ':' });
                    if (xy.Length != 2)
                    {
                        其他_.打印("扔药仓库管理员坐标设置错误");
                        return;
                    }
                    var x = int.Parse(xy[0].Trim());
                    var y = int.Parse(xy[1].Trim());
                    var 扔药人物 = new 挂机人物(扔药窗口句柄, cts, 挂机项目_.扔药, 扔药空格数量, 扔药剩余数量, 0, new 坐标_(x, y));
                    this.挂机人物列表.Add(扔药人物);
                }
                catch
                {
                    其他_.打印("扔药设置发生错误");
                    return;
                }
            }
            else if (是捡药)
            {
                调整窗口(捡药窗口句柄);
                其他_.延迟(500);
                //窗口_.置顶窗口(挂机程序句柄);

                try
                {
                    var 捡药空格数量 = int.Parse(this.捡药包裹空格数.Text);
                    var 捡药坐标文本 = this.捡药坐标.Text.Trim();
                    var xy = 捡药坐标文本.Split(new char[] { ':' });

                    if (xy.Length != 2)
                    {
                        其他_.打印("捡药仓库管理员坐标设置错误");
                        return;
                    }
                    var x = int.Parse(xy[0].Trim());
                    var y = int.Parse(xy[1].Trim());
                    var 捡药人物 = new 挂机人物(捡药窗口句柄, cts, 挂机项目_.捡药, 捡药空格数量, 0, new 坐标_(x, y));
                    this.挂机人物列表.Add(捡药人物);
                }
                catch
                {
                    其他_.打印("捡药设置发生错误");
                    return;
                }
            }
            else
            {
                其他_.打印("未选中挂机项目");
                return;
            }

            其他_.延迟(其他_.时长_5000);
            当前挂机人物索引 = 0;
            执行线程 = new 线程_(() =>
            {
                var 当前人物 = this.挂机人物列表[当前挂机人物索引];
                var 结果 = 当前人物.执行(this.挂机人物列表);
                if (!结果)
                {
                    return false;
                }

                if (!当前人物.连续执行任务)
                {
                    当前挂机人物索引 = 当前挂机人物索引 < this.挂机人物列表.Count - 1 ?
                    当前挂机人物索引 + 1 : 0;
                }
                return true;
            }, cts, false, "挂机执行主线程", true);

            启动挂机();
        }

        private void 暂停命令执行()
        {
            if (!开始或暂停.IsEnabled) return;

            if (开始或暂停.Content.ToString() != "暂停(Ctrl + ↓)" && 开始或暂停.Content.ToString() != "恢复(Ctrl + ↓)") return;
            var 命令名 = 开始或暂停.Content.ToString();// == "暂停" ? "恢复" : "暂停";
            其他_.打印("点击了" + 命令名);

            开始或暂停.Content = 命令名 == "暂停(Ctrl + ↓)" ? "恢复(Ctrl + ↓)" : "暂停(Ctrl + ↓)";
            if (命令名 == "暂停(Ctrl + ↓)")
            {
                其他_.打印("执行暂停命令");
                if (执行线程 != null)
                {
                    结束.IsEnabled = true;
                    cts.Cancel();
                    执行线程.暂停();
                }
            }
            else
            {
                其他_.打印("执行恢复命令");
                cts = new CancellationTokenSource();
                foreach (var 人物 in this.挂机人物列表)
                {
                    人物.cts = cts;
                }
                当前挂机人物索引 = 0;
                执行线程 = new 线程_(() =>
                {
                    var 当前人物 = this.挂机人物列表[当前挂机人物索引];
                    var 结果 = 当前人物.执行(this.挂机人物列表);
                    if (!结果)
                    {
                        return false;
                    }

                    if (!当前人物.连续执行任务)
                    {
                        当前挂机人物索引 = 当前挂机人物索引 < this.挂机人物列表.Count - 1 ?
                        当前挂机人物索引 + 1 : 0;
                    }
                    return true;
                }, cts, false, "挂机执行主线程", true);

                启动挂机();
            }
        }

        private void 结束命令执行()
        {
            其他_.打印("点击了结束命令执行");
            cts.Cancel();
            if (执行线程 != null) 执行线程.退出();
            开始或暂停.Content = "开始(Ctrl + ←)";
            功能总面板.IsEnabled = true;
            开始或暂停.IsEnabled = true;
            结束.IsEnabled = false;
        }

        private void 买药_Checked(object sender, RoutedEventArgs e)
        {
            扔药捡药面板.IsEnabled = false;
            买药设置面板.IsEnabled = true;
            买药捕获.IsEnabled = true;
            tabControl.SelectedIndex = 0;
        }

        private void 扔药_Checked(object sender, RoutedEventArgs e)
        {
            买药.IsEnabled = false;
            买药设置面板.IsEnabled = false;
            扔药捕获.IsEnabled = true;
            扔药设置面板.IsEnabled = true;
            tabControl.SelectedIndex = 1;
        }

        private void 捡药_Checked(object sender, RoutedEventArgs e)
        {
            买药.IsEnabled = false;
            买药设置面板.IsEnabled = false;
            捡药捕获.IsEnabled = true;
            捡药设置面板.IsEnabled = true;
            tabControl.SelectedIndex = 2;
        }

        private void 买药_Unchecked(object sender, RoutedEventArgs e)
        {
            扔药捡药面板.IsEnabled = true;
            买药设置面板.IsEnabled = false;
            扔药.IsEnabled = true;
            捡药.IsEnabled = true;
            买药捕获.IsEnabled = false;
            tabControl.SelectedIndex = 1;
            if (买药捕获.Foreground == 蓝色笔刷)
            {
                买药捕获.Foreground = 默认笔刷;
            }
        }

        private void 扔药_Unchecked(object sender, RoutedEventArgs e)
        {
            扔药设置面板.IsEnabled = false;
            扔药捕获.IsEnabled = false;
            if (扔药捕获.Foreground == 蓝色笔刷)
            {
                扔药捕获.Foreground = 默认笔刷;
            }

            if (捡药.IsChecked == false)
            {
                买药.IsEnabled = true;
                tabControl.SelectedIndex = 0;
            }
            else
            {
                tabControl.SelectedItem = 2;
                捡药捕获.IsEnabled = true;
            }
        }

        private void 捡药_Unchecked(object sender, RoutedEventArgs e)
        {
            捡药设置面板.IsEnabled = false;
            捡药捕获.IsEnabled = false;
            if (捡药捕获.Foreground == 蓝色笔刷)
            {
                捡药捕获.Foreground = 默认笔刷;
            }
            if (扔药.IsChecked == false)
            {
                买药捕获.IsEnabled = false;
                买药.IsEnabled = true;
                tabControl.SelectedIndex = 0;
            }
            else
            {
                扔药捕获.IsEnabled = true;
                tabControl.SelectedIndex = 1;
            }
        }

        private void 买药捕获_MouseMove(object sender, MouseEventArgs e)
        {
            捕获_鼠标移动(买药捕获, e);
        }

        private void 捕获_鼠标移动(Button 按钮, MouseEventArgs e)
        {
            if (_isDragging)
            {
                Point currentPosition = e.GetPosition(this);
                double offsetX = currentPosition.X - _startPoint.X;
                double offsetY = currentPosition.Y - _startPoint.Y;
                Canvas.SetLeft(按钮, Canvas.GetLeft(按钮) + offsetX);
                Canvas.SetTop(按钮, Canvas.GetTop(按钮) + offsetY);
                _startPoint = currentPosition;
            }
        }

        private void 买药捕获_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            捕获_鼠标按下(买药捕获, e);
        }

        private void 捕获_鼠标按下(Button 按钮, MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                _startPoint = e.GetPosition(this);
                _isDragging = true;
                this.Cursor = Cursors.Hand;
                按钮.CaptureMouse();
            }
        }

        private void 买药捕获_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            捕获_鼠标松开(买药捕获, "买买买买_〖买药〗", out 买药窗口句柄);
        }

        private void 捕获_鼠标松开(Button 按钮, string 新标题, out IntPtr 窗口句柄)
        {
            if (_isDragging)
            {
                _isDragging = false;
                按钮.ReleaseMouseCapture();
                // 获取鼠标当前屏幕坐标
                Point screenPoint = Mouse.GetPosition(null);
                Point winformsPoint = 按钮.PointToScreen(screenPoint);
                窗口句柄 = 窗口_.WindowFromPoint(new 窗口_.POINT((int)winformsPoint.X, (int)winformsPoint.Y));
                var 窗口类名 = 窗口_.获取窗口类名(窗口句柄);
                if (窗口类名 != 游戏窗口类名)
                {
                    其他_.打印("捕获的窗口不正确");
                    return;
                }
                窗口_.SetWindowText(窗口句柄, 新标题);
                默认笔刷 = 按钮.Foreground;
                按钮.Foreground = 蓝色笔刷;
                按钮.IsEnabled = false;
                其他_.打印("捕获窗口标题为: " + 新标题);
                开始或暂停.IsEnabled = true;
            }
            else
            {
                窗口句柄 = IntPtr.Zero;
            }
            this.Cursor = Cursors.Arrow;
        }

        private void 扔药捕获_MouseMove(object sender, MouseEventArgs e)
        {
            捕获_鼠标移动(扔药捕获, e);
        }

        private void 扔药捕获_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            捕获_鼠标按下(扔药捕获, e);
        }

        private void 扔药捕获_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            捕获_鼠标松开(扔药捕获, "扔扔扔扔_〖扔药〗", out 扔药窗口句柄);
        }

        private void 捡药捕获_MouseMove(object sender, MouseEventArgs e)
        {
            捕获_鼠标移动(捡药捕获, e);
        }

        private void 捡药捕获_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            捕获_鼠标按下(捡药捕获, e);
        }

        private void 捡药捕获_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            捕获_鼠标松开(捡药捕获, "捡捡捡捡_〖捡药〗", out 捡药窗口句柄);
        }

        private void 开始或暂停_Click(object sender, RoutedEventArgs e)
        {
            var 是开始 = 开始或暂停.Content.ToString();

            if (是开始 == "开始(Ctrl + ←)")
            {
                开始命令执行();
            }
            else
            {
                暂停命令执行();
            }
            结束.IsEnabled = true;
        }

        private void 启动挂机()
        {
            if (this.挂机人物列表.Count > 0)
            {
                执行线程.启动();
            }
            else
            {
                其他_.打印("没有启动任何模拟器");
            }
        }

        public void 调整窗口(IntPtr H)
        {
            窗口_.GetClientRect(H, out var clientRect);
            窗口_.GetWindowRect(H, out var windowRect);

            int currentClientWidth = clientRect.Right - clientRect.Left;
            int currentClientHeight = clientRect.Bottom - clientRect.Top;
            int windowWidth = windowRect.Right - windowRect.Left;
            int windowHeight = windowRect.Bottom - windowRect.Top;

            // 计算窗口边框和标题栏的大小
            int borderWidth = windowWidth - currentClientWidth;
            int borderHeight = windowHeight - currentClientHeight;

            // 计算新的窗口大小
            const int targetClientWidth = 1280;
            const int targetClientHeight = 800;
            int newWindowWidth = targetClientWidth + borderWidth;
            int newWindowHeight = targetClientHeight + borderHeight;

            if (窗口_.窗口是最小化的(H))
            {
                窗口_.恢复窗口(H);
                其他_.延迟(其他_.时长_1000);
            }
            //窗口_.置顶窗口(H);
            窗口_.SetWindowPos(H, 0, 0, 0, newWindowWidth, newWindowHeight, 窗口_. SWP_NOZORDER | 窗口_.SWP_SHOWWINDOW);
        }

        private void 结束_Click(object sender, RoutedEventArgs e)
        {
            结束命令执行();
        }

        private void 主窗口_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (买药窗口句柄 != IntPtr.Zero)
            {
                窗口_.取消置顶窗口(买药窗口句柄);
            }
            if (扔药窗口句柄 != IntPtr.Zero)
            {
                窗口_.取消置顶窗口(扔药窗口句柄);
            }
            if (捡药窗口句柄 != IntPtr.Zero)
            {
                窗口_.取消置顶窗口(捡药窗口句柄);
            }
            IntPtr hwnd = new WindowInteropHelper(this).Handle;
            UnregisterHotKey(hwnd, _开始_);
            UnregisterHotKey(hwnd, _暂停_);
            UnregisterHotKey(hwnd, _结束_);

            // 读取窗口位置
            Properties.Settings.Default.左边 = this.Left;
            Properties.Settings.Default.上边 = this.Top;
            Properties.Settings.Default.高度 = this.Height;
            Properties.Settings.Default.宽度 = this.Width;

            Properties.Settings.Default.买药 = 买药.IsChecked == true;
            Properties.Settings.Default.捡药 = 捡药.IsChecked == true;
            Properties.Settings.Default.扔药 = 扔药.IsChecked == true;

            Properties.Settings.Default.运行速率 = 运行速率.Text;
            Properties.Settings.Default.买药包裹空格数量 = 买药包裹空格数量.Text;
            Properties.Settings.Default.买药金币总量 = 买药金币总量.Text;
            Properties.Settings.Default.扔药包裹空格数 = 扔药包裹空格数.Text;
            Properties.Settings.Default.扔药剩余数量 = 扔药剩余数量.Text;
            Properties.Settings.Default.扔药坐标 = 扔药坐标.Text;
            Properties.Settings.Default.捡药包裹空格数 = 捡药包裹空格数.Text;
            Properties.Settings.Default.捡药坐标 = 捡药坐标.Text;
            Properties.Settings.Default.Save();
        }

        private void 运行速率_LostFocus(object sender, RoutedEventArgs e)
        {
            if (其他_.IsTextAllowed(((TextBox)sender).Text))
            {
                其他_.运行速率 = double.Parse(((TextBox)sender).Text);
            }
            else
            {
                ((TextBox)sender).Text = 其他_.运行速率.ToString();
            }
        }
    }
}
